/*
 * Vec3.cpp.inl
 *
 *  Created on: 19.09.2009
 *      Author: christoph
 */

// this file is included by its header file to satisfy the compiler

template <typename Real>
Vec3<Real>::Vec3() {
	data[0] = 0;
	data[1] = 0;
	data[2] = 0;
}

template <typename Real>
Vec3<Real>::Vec3( const Vec2<Real>& v2V, const Real rZ ) {
	data[0] = v2V.x();
	data[1] = v2V.y();
	data[2] = rZ;
}

template < typename Real >
Vec3<Real>::Vec3( const Real rX, const Real rY, const Real rZ ) {
	data[0] = rX;
	data[1] = rY;
	data[2] = rZ;
}

template <typename Real>
Vec3<Real>::Vec3( const Vec3<Real>& v3V ) {
	data[0] = v3V.x();
	data[1] = v3V.y();
	data[2] = v3V.z();
}

template <typename Real>
Vec3<Real>::~Vec3() {
}

template <typename Real>
Real Vec3<Real>::x() const {
	return data[0];
}

template <typename Real>
Real& Vec3<Real>::x() {
	return data[0];
}

template <typename Real>
Real Vec3<Real>::y() const {
	return data[1];
}

template <typename Real>
Real& Vec3<Real>::y() {
	return data[1];
}

template <typename Real>
Real Vec3<Real>::z() const {
	return data[2];
}

template <typename Real>
Real& Vec3<Real>::z() {
	return data[2];
}

template <typename Real>
const Real Vec3<Real>::operator [] ( int iIndex ) const {
	return data[iIndex];
}

template <typename Real>
Real& Vec3<Real>::operator [] ( int iIndex ) {
	return data[iIndex];
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator + ( const Vec3<Real>& vRhs ) const {
	return Vec3<Real>( data[0] + vRhs.data[0], data[1] + vRhs.data[1], data[2] + vRhs.data[2] );
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator - ( const Vec3<Real>& vRhs ) const {
	return Vec3<Real>( data[0] - vRhs.data[0], data[1] - vRhs.data[1], data[2] - vRhs.data[2] );
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator * ( const Real rRhs ) const {
	return Vec3<Real>( data[0] * rRhs, data[1] * rRhs, data[2] * rRhs );
}

template <typename Real>
Real Vec3<Real>::operator * ( const Vec3<Real>& vRhs ) const {
	data[0] * vRhs.data[0] + data[1] * vRhs.data[1] + data[2] * vRhs.data[2];
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator / ( const Real rRhs ) const {
	return Vec3<Real>( data[0] / rRhs, data[1] / rRhs, data[2] / rRhs );
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator - () const {
	return Vec3<Real>( -data[0], -data[1], -data[2] );
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator += ( const Vec3<Real>& vRhs ) {
	data[0] += vRhs.data[0];
	data[1] += vRhs.data[1];
	data[2] += vRhs.data[2];
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator -= ( const Vec3<Real>& vRhs ) {
	data[0] -= vRhs.data[0];
	data[1] -= vRhs.data[1];
	data[2] -= vRhs.data[2];
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator *= ( const Real rRhs ) {
	data[0] *= rRhs;
	data[1] *= rRhs;
	data[2] *= rRhs;
}

template <typename Real>
Vec3<Real> Vec3<Real>::operator /= ( const Real rRhs ) {
	data[0] /= rRhs;
	data[1] /= rRhs;
	data[2] /= rRhs;
}

// TODO comparison operations
template <typename Real>
bool Vec3<Real>::operator == ( const Vec3<Real>& v3Rhs ) const {
	return compareArrays( v3Rhs ) == 0;
}

template <typename Real>
bool Vec3<Real>::operator != ( const Vec3<Real>& v3Rhs ) const {
	return compareArrays( v3Rhs ) != 0;
}

template <typename Real>
bool Vec3<Real>::operator < ( const Vec3<Real>& v3Rhs ) const {
	return compareArrays( v3Rhs ) < 0;
}

template <typename Real>
bool Vec3<Real>::operator > ( const Vec3<Real>& v3Rhs ) const {
	return compareArrays( v3Rhs ) > 0;
}

template <typename Real>
bool Vec3<Real>::operator <= ( const Vec3<Real>& v3Rhs ) const {
	return compareArrays( v3Rhs ) <= 0;
}

template <typename Real>
bool Vec3<Real>::operator >= ( const Vec3<Real>& v3Rhs ) const {
	return compareArrays( v3Rhs ) >= 0;
}

template <typename Real>
Real Vec3<Real>::length() const {
	return Math<Real>::Sqrt( data[0] * data[0] + data[1] * data[1] + data[2] * data[2] );
}

template <typename Real>
Real Vec3<Real>::squaredLength() const {
	return data[0] * data[0] + data[1] * data[1] + data[2] * data[2];
}

template <typename Real>
Real Vec3<Real>::normalize() {
	Real length = this->length();
	if ( length > 0.0 ) {
		data[0] /= length;
		data[1] /= length;
		data[2] /= length;
	}
	return length;
}

template <typename Real>
Real Vec3<Real>::dot( const Vec3& v2A ) const {
	return this->data[0] * v2A.data[0] + this->data[1] * v2A.data[1] + this->data[2] * v2A.data[2];
}

// Vec3 specific
template <typename Real>
Vec3<Real> Vec3<Real>::cross( const Vec3<Real>& v3V ) const {
	return Vec3<Real>( 	data[1] * v3V.data[2] - data[2] * v3V.data[1],
						data[2] * v3V.data[0] - data[0] * v3V.data[2],
						data[0] * v3V.data[1] - data[1] * v3V.data[0] );
}

template <typename Real>
Vec3<Real> Vec3<Real>::unitCross( const Vec3<Real>& v3V ) const {
	Vec3<Real> result = cross( v3V );
	result.normalize();
	return result;
}


template <typename Real>
void Vec3<Real>::orthonormalize( Vec3<Real>& v3V ) {
	// TODO implement me
}

template <typename Real>
void Vec3<Real>::generateOrthonormalBasis( Vec3<Real>& v3U, Vec3<Real>& v3V, Vec3<Real>& v3W, bool bUnitLengthW ) {
	// TODO implement me
}

template <class Real>
int Vec3<Real>::compareArrays( const Vec3<Real>& rkV ) const {
    return memcmp( data, rkV.data, 3 * sizeof( Real ) );
}
